#pragma once
#include "PackageCache.hpp"
#include <iostream>

PackageCache PackageCache::_Pack;

void  PackageCache::ReleasePackageSpan(Span* span)
{
    if(span->_n > Package_Num - 1)
    {
        //大于128页了 根据span的id，得到对应的内存地址
        void* ptr = (void*)(span->_pageID << Pack_Shift);
        SystemFree(ptr);
        // delete span;
        PackageCache::create()->_objspan.Delete(span);
        return;
    }
    //先向pc中的左边合并
    while(1)
    {
        PageID leftPageId = span->_pageID-1;
        auto ret = _idHashMap.find(leftPageId);
        if(ret == _idHashMap.end())
        {
            break;
        }
        Span* retspan = ret->second;
        if(retspan->isUse==true)
        {
            break;
        }
        //不能大于128页
        if(retspan->_n + span->_n > Package_Num-1)
        {
            break;
        }
        //开始合并
        span->_pageID = retspan->_pageID;
        span->_n += retspan->_n;
        _splist[retspan->_n].erase(retspan);
        span->isUse = false;

        // delete retspan;
        PackageCache::create()->_objspan.Delete(retspan);
    }
    //在往右边进行合并
    while(1)
    {
        PageID rightID = span->_n + span->_pageID;
        auto ret = _idHashMap.find(rightID);
        if(ret == _idHashMap.end())
        {
            break;
        }
        Span* rightSpan = ret->second;
        if(rightSpan->isUse==true)
        {
            break;
        }
        //不能大于128页
        if(rightSpan->_n + span->_n > Package_Num-1)
        {
            break;
        }
        //开始合并
        span->_pageID = rightSpan->_pageID;
        span->_n +=rightSpan->_n;
        
        _splist[rightSpan->_n].erase(rightSpan);
        PackageCache::create()->_objspan.Delete(rightSpan);
        // delete rightSpan;
    }
    //把合并成的span放回到pc中
    _idHashMap[span->_pageID] = span;
    _idHashMap[span->_pageID+span->_n-1] = span;
    _splist[span->_n].PushFront(span);
}

Span* PackageCache::MaptoSpan(void* start)
{
    std::unique_lock<std::mutex> _mutex1(_mutex);
    PageID id = ((PageID)start) >> Pack_Shift;
    auto ret = _idHashMap.find(id);
    if( ret == _idHashMap.end())
    {
        //不存在对应的映射关系
        assert(false);
        return nullptr;
    }
    return ret->second;
}

Span* PackageCache::NewSpan(size_t k)
{
    if(k > Package_Num-1)
    {
        Span* newspan = PackageCache::create()->_objspan.New();
        return newspan;
    }

    assert(k > 0 && k < Package_Num);
    if(!_splist[k].Empty())
    {
        Span* p1 = _splist[k].popFront();
        for(PageID i = 0; i < p1->_n;i++)
        {
            _idHashMap[i+p1->_pageID] = p1;
        }
        return p1;
    }
    //不存在就要往下面找一个大的进行切割
    for(int i = k+1; i < Package_Num;i++)
    {
        if(!_splist[i].Empty())
        {
            //把大块的进行切割处理
            Span* span = _splist[i].popFront();
            
            // Span* newSpan = new Span;
            Span* newSpan = PackageCache::create()->_objspan.New();

            newSpan->_pageID = span->_pageID;
            newSpan->_n = k;

            //将分配好的newspan添加到unordered_map
            for(PageID i = 0; i < newSpan->_n;i++)
            {
                //将Pageid与span块映射到一起
                _idHashMap[i+newSpan->_pageID] = newSpan;
            }
            span->_pageID += k;
            span->_n -= k;

            //将pc中剩下的span页映射到map中去
            _idHashMap[span->_pageID] = span;
            _idHashMap[span->_pageID+span->_n-1] = span;

            //把切割剩下的插入回哈希表中去
            _splist[span->_n].PushFront(span);
            return newSpan;
    }
    //都不行，从系统中申请128页大小，然后复用代码
    void* ptr = SystemAlloc(Package_Num-1);
    // Span* bigspan = new Span;
    Span* bigspan = PackageCache::create()->_objspan.New();
    bigspan->_pageID = (PageID)ptr >> Pack_Shift;
    bigspan->_n = Package_Num - 1;

    return NewSpan(k);
}